package com.seezoon.infrastructure.tcp.codec;

import com.seezoon.infrastructure.error.ErrorCode;
import com.seezoon.infrastructure.exception.ExceptionFactory;
import com.seezoon.infrastructure.tcp.common.MessageConstants;
import com.seezoon.infrastructure.utils.BcdUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;

@Slf4j
public class MessageEncoder extends MessageToByteEncoder<JTMessage> {

    private final int maxBodyLength = 1023;

    @Override
    protected void encode(ChannelHandlerContext ctx, JTMessage msg, ByteBuf out) throws Exception {
        if (msg.getBodyLength() > maxBodyLength) {
            log.error("tcp message body too large msgId:{},serialNo:{},current length is {}", msg.getMsgId(),
                    msg.getSerialNo(), msg.getBodyLength());
            throw ExceptionFactory.bizException(ErrorCode.TCP_MESSAGE_TOO_LARGE);
        }
        // 1. 创建临时缓冲区计算校验码
        ByteBuf tempBuf = Unpooled.buffer();
        // 2. 写入消息头（不包括起始符）
        tempBuf.writeShort(msg.getMsgId());
        tempBuf.writeShort(msg.getMsgProperties());
        byte[] serialNo = BcdUtils.stringToBcd(msg.getSerialNo());
        if (serialNo.length != 6) {
            log.error("tcp message serialNo length != 6, msgId:{},serialNo:{},current length is {}", msg.getMsgId(),
                    msg.getSerialNo(), serialNo.length);
            throw ExceptionFactory.bizException(ErrorCode.TCP_MESSAGE_FORMAT_ERROR);
        }
        tempBuf.writeBytes(serialNo); // 6字节
        tempBuf.writeShort(msg.getMsgSerialNo());
        // 3. 如果分包，写入分包信息
        if (msg.hasSubPackage()) {
            tempBuf.writeShort(msg.getPackageTotal());
            tempBuf.writeShort(msg.getPackageNo());
        }
        // 4. 写入消息体
        if (msg.getBody() != null) {
            tempBuf.writeBytes(msg.getBody());
        }
        // 5. 计算校验码 (XOR 从消息头到消息体结束)
        byte checksum = calculateChecksum(tempBuf);
        tempBuf.writeByte(checksum);
        // 6. 构建最终消息帧
        // 为了打印发送的字节
        int writeStartIndex = out.writerIndex();
        out.writeByte(MessageConstants.MAGIC_0X_7E);  // 起始符
        out.writeBytes(escapeBuffer(tempBuf));        // 写入所有数据
        out.writeByte(MessageConstants.MAGIC_0X_7E);  // 结束符
        if (log.isDebugEnabled()) {
            byte[] printBuf = new byte[out.writerIndex() - writeStartIndex];
            out.getBytes(writeStartIndex, printBuf);
            log.debug("tcp message send message is [{}]", Hex.encodeHexString(printBuf));
        }
        // 7. 释放临时缓冲区（可选）
        tempBuf.release();
    }

    // JT808 校验码计算 (XOR)
    private byte calculateChecksum(ByteBuf data) {
        if (data.readableBytes() == 0) {
            return 0;
        }
        byte checksum = data.getByte(0);
        for (int i = 1; i < data.readableBytes(); i++) {
            checksum ^= data.getByte(i);
        }
        return checksum;
    }

    /**
     * 转义规则
     *
     * @param source
     * @return
     */
    private ByteBuf escapeBuffer(ByteBuf source) {
        ByteBuf target = Unpooled.buffer(source.readableBytes() * 2); // 最大可能扩展两倍
        int len = source.readableBytes();
        for (int i = 0; i < len; i++) {
            byte b = source.getByte(i);
            if (b == MessageConstants.MAGIC_0X_7D) {
                target.writeByte(MessageConstants.MAGIC_0X_7D);
                target.writeByte(MessageConstants.TANS_0X01);
            } else if (b == MessageConstants.MAGIC_0X_7E) {
                target.writeByte(MessageConstants.MAGIC_0X_7D);
                target.writeByte(MessageConstants.TANS_0X02);
            } else {
                target.writeByte(b);
            }
        }
        return target;
    }
}